﻿namespace SenenFernandez.UniversalExtensions
{
    using System;
    using System.Collections.Generic;
    using System.Windows.Input;

    /// <summary>
    /// This class allows delegating the commanding logic to methods passed as parameters,
    /// and enables a View to bind commands to objects that are not part of the element tree.
    /// </summary>
    public class SmartCommand : ICommand
    {
        private readonly Action execute;
        private readonly Func<bool> canExecute;

        /// <summary>
        /// Initializes a new instance of <see cref="SmartCommand"/>.
        /// </summary>
        public SmartCommand(Action executeMethod, Func<bool> canExecuteMethod = null)
        {
            if (executeMethod != null)
            {
                execute = executeMethod;
                canExecute = canExecuteMethod;
            }
        }

        /// <summary>
        /// Method to determine if the command can be executed
        /// </summary>
        public bool CanExecute()
        {
            if (canExecute != null)
            {
                return canExecute();
            }
            return true;
        }

        /// <summary>
        /// Execution of the command
        /// </summary>
        public void Execute()
        {
            if (execute != null)
            {
                execute();
            }
        }

        /// <summary>
        /// ICommand.CanExecuteChanged implementation
        /// </summary>
        public event EventHandler CanExecuteChanged;

        /// <summary>
        /// Defines the method that determines whether the command can execute in its current state.
        /// </summary>
        bool ICommand.CanExecute(object parameter)
        {
            return CanExecute();
        }

        /// <summary>
        /// Defines the method to be called when the command is invoked.
        /// </summary>
        void ICommand.Execute(object parameter)
        {
            Execute();
        }
    }

    /// <summary>
    /// This class allows delegating the commanding logic to methods passed as parameters,
    /// and enables a View to bind commands to objects that are not part of the element tree.
    /// </summary>
    public class SmartCommand<T> : ICommand where T : class
    {
        private readonly Action<T> execute;
        private readonly Func<T, bool> canExecute;

        /// <summary>
        /// Initializes a new instance of <see cref="SmartCommand{T}"/>.
        /// </summary>
        public SmartCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod = null)
        {
            if (executeMethod != null)
            {
                execute = executeMethod;
                canExecute = canExecuteMethod;
            }
        }

        /// <summary>
        /// Method to determine if the command can be executed
        /// </summary>
        public bool CanExecute(T parameter)
        {
            if (canExecute != null)
            {
                return canExecute(parameter);
            }
            return true;
        }

        /// <summary>
        /// Execution of the command
        /// </summary>
        public void Execute(T parameter)
        {
            if (execute != null)
            {
                execute(parameter);
            }
        }

        /// <summary>
        /// ICommand.CanExecuteChanged implementation
        /// </summary>
        public event EventHandler CanExecuteChanged;

        /// <summary>
        /// Defines the method that determines whether the command can execute in its current state.
        /// </summary>
        public bool CanExecute(object parameter)
        {
            return CanExecute(parameter as T);
        }

        /// <summary>
        /// Defines the method to be called when the command is invoked.
        /// </summary>
        void ICommand.Execute(object parameter)
        {
            Execute((T)parameter);
        }
    }
}